#include "tools.h"
#include "uinteger.h"

/** 测试设置和比较 */
static bool Test_Set() {
	bool r = true;

	{ // 设置单个整数
		UInteger a;

		UInteger_FromUInt(&a, 3);
		
		bool rz = UInteger_CompareUInt(&a, 3) == 0 &&
		          UInteger_CompareUInt(&a, 2) > 0 &&
				  UInteger_CompareUInt(&a, 4) < 0;
		r = rz && r;
	}

	{
		UInteger a;

		uint32_t v[3] = { 0x123345, 0x12, 0xbac14570 };
		uint32_t gv[3] = { 0x123345, 0x13, 0xbac14570 };
		uint32_t sv[3] = { 0x123345, 0x10, 0xbac14570 };

		UInteger_FromUInts(&a, v, 3);

		bool rz = UInteger_CompareUInts(&a, v, 3) == 0 &&
		          UInteger_CompareUInts(&a, sv, 3) > 0 &&
				  UInteger_CompareUInts(&a, gv, 3) < 0 ;
		r = rz && r;
	}
	return r;
}


static bool Test_Add() {
	bool r = true;

	{ // 普通加法
		uint32_t a[3] = { 0x1234, 0x78, 0x4000 };
		uint32_t b[3] = { 0x1234, 0, 0x32 };
		uint32_t c[3] = { 0x2468, 0x78, 0x4032 };
		
		UInteger sa, sb, sc;
		UInteger_FromUInts(&sa, a, 3);
		UInteger_FromUInts(&sb, b, 3);
		
		bool rz = UInteger_Add(&sa, &sb, &sc);
		rz = rz && UInteger_CompareUInts(&sc, c, 3) == 0;

		rz = rz && r;
	}

	{	// 进位
		uint32_t a[3] = {0x70102301, 0xFFFFFFFF,0xEEEEEEEE};
		uint32_t b[3] = {0xE3129822, 0, 0x22222222};
		uint32_t c[4] = {1, 0x5322bb24, 0, 0x11111110} ;
		
		UInteger sa, sb, sc;
		UInteger_FromUInts(&sa, a, 3);
		UInteger_FromUInts(&sb, b, 3);

		bool rz = UInteger_Add(&sa, &sb, &sc);
		r = rz && UInteger_CompareUInts(&sc, c, 4) == 0 && r;
	}

	{	// 溢出
		uint32_t b[3] = { 0, 0, 2};
		uint32_t c[3] = { 0, 0, 1 };
			
		UInteger sa, sb, sc;
		UInteger_Fill(&sa, 0xFFFFFFFF);
		UInteger_FromUInts(&sb, b, 3);

		bool rz = UInteger_Add(&sa, &sb, &sc);
		r = !rz && UInteger_CompareUInts(&sc, c, 3) == 0 && r;
	}

	return r;
}

static bool Test_ModAdd() {
	bool r = true;

	{ // 普通加法
		uint32_t a[3] = {1,1,1};
		uint32_t b[3] = {2,2,2};
		const uint32_t c[3] = {0, 0, 0} ;
		uint32_t m[3] = {0, 0, 3};

		UInteger sa, sb, sc, sm;
		UInteger_FromUInts(&sa, a, 3);
		UInteger_FromUInts(&sb, b, 3);
		UInteger_FromUInts(&sm, m, 3);
		
		UInteger_ModAdd(&sa, &sb, &sm, &sc);
		r = UInteger_CompareUInts(&sc, c, 3) == 0 && r;
	}

	{	// 进位
		uint32_t a[3] = {1, 0xFFFFFFFF,0xEEEEEEEE};
		uint32_t b[3] = {2, 0, 0x22222222};
		const uint32_t c[3] = {0, 0x23, 0x11111119};
		uint32_t m[3] = {0, 0x34, 0x0D};

		UInteger sa, sb, sc, sm;
		UInteger_FromUInts(&sa, a, 3);
		UInteger_FromUInts(&sb, b, 3);
		UInteger_FromUInts(&sm, m, 3);

		UInteger_ModAdd(&sa, &sb, &sm, &sc);
		r = UInteger_CompareUInts(&sc, c, 3) == 0 && r;

	}

	{	// 溢出
		const uint32_t m[3] = {0x1ec, 0x5e31b9e1, 0x2128d36a};

		UInteger sa, sb, sc, sm, sd;
		UInteger_Fill(&sa, 0xFE341221);
		UInteger_Fill(&sb, 0x23CE3412);
		UInteger_FromUInts(&sm, m, 3);

		UInteger_FromUInt(&sd, 0);

		UInteger_ModAdd(&sa, &sb, &sm, &sc);
		UInteger_ModAdd(&sa, &sd, &sm, &sd);
		UInteger_ModAdd(&sb, &sd, &sm, &sd);

		r = UInteger_Compare(&sc, &sd) == 0 && r;
	}

	return r;
}

static bool Test_ModSub() {
	bool r = true;

	{ // 普通加法
		uint32_t a[3] = {1,1,1};
		uint32_t b[3] = {2,2,2};
		const uint32_t c[3] = {0, 0, 0} ;
		uint32_t m[3] = {0, 0, 3};

		UInteger sa, sb, sc, sm;
		UInteger_FromUInts(&sa, a, 3);
		UInteger_FromUInts(&sb, b, 3);
		UInteger_FromUInts(&sm, m, 3);
		
		UInteger_ModAdd(&sa, &sb, &sm, &sc);
		r = UInteger_CompareUInts(&sc, c, 3) == 0 && r;
	}

	{	// 进位
		uint32_t a[3] = {1, 0xFFFFFFFF,0xEEEEEEEE};
		uint32_t b[3] = {2, 0, 0x22222222};
		const uint32_t c[3] = {0, 0x23, 0x11111119};
		uint32_t m[3] = {0, 0x34, 0x0D};

		UInteger sa, sb, sc, sm;
		UInteger_FromUInts(&sa, a, 3);
		UInteger_FromUInts(&sb, b, 3);
		UInteger_FromUInts(&sm, m, 3);

		UInteger_ModAdd(&sa, &sb, &sm, &sc);
		r = UInteger_CompareUInts(&sc, c, 3) == 0 && r;

	}

	{	// 溢出
		const uint32_t m[3] = {0x1ec, 0x5e31b9e1, 0x2128d36a};

		UInteger sa, sb, sc, sm, sd;
		UInteger_Fill(&sa, 0xFE341221);
		UInteger_Fill(&sb, 0x23CE3412);
		UInteger_FromUInts(&sm, m, 3);

		UInteger_FromUInt(&sd, 0);

		UInteger_ModAdd(&sa, &sb, &sm, &sc);
		UInteger_ModAdd(&sa, &sd, &sm, &sd);
		UInteger_ModAdd(&sb, &sd, &sm, &sd);

		r = UInteger_Compare(&sc, &sd) == 0 && r;
	}

	return r;
}

bool Test_ModInv() {
	bool r;

	{ //
		UInteger sa, sm, sb;
		UInteger_FromUInt(&sa, 2);
		UInteger_FromUInt(&sm, 23);

		bool rz = UInteger_ModInv(&sa, &sm, &sb);
		r = rz && UInteger_CompareUInt(&sb, 12) == 0 && r;

	}
	return r;
}

bool Test_BitOp() {
	bool r = true;

	{	// 
		UInteger a, b, sum, product, f;
		UInteger_FromUInt(&a, 0x1B); 
		UInteger_FromUInt(&b, 0x13); 
		UInteger_FromUInt(&sum, 0x08); 
		UInteger_FromUInt(&product, 0x08); 
		UInteger_FromUInt(&f, 0x25); 

		UInteger v;
		UInteger_BitModAdd(&a, &b, &f, &v);

		r = UInteger_Compare(&sum, &v) == 0 && r;

		UInteger_BitModMul(&a, &b, &f, &v);

		r = UInteger_Compare(&product, &v) == 0 && r;
	}

	return true;
}

bool SM_Test_UInteger() {
	bool r = true;

	r = SM_TEST(Test_Set()) && r;

	r = SM_TEST(Test_Add()) && r;

	r = SM_TEST(Test_ModAdd()) && r;
	//r = SM_TEST(Test_ModSub()) && r;
	r = SM_TEST(Test_ModInv()) && r;
	r = SM_TEST(Test_BitOp()) && r;
	
	return r;
}
